function DiPoint(frame)
{
	var returner = 
	{
		frame: frame,
		x: 0,
		y: 0,
		
		isTouched: function(touchX, touchY)
		{
			return touchX > this.x && touchX < this.x +image[this.frame].width 
               &&  touchY > this.y && touchY < this.y +image[this.frame].height
		},
					
		changeX: function(amount) {this.x += amount;},
		changeY: function(amount) {this.y += amount;},
					
		setLeft  : function(amount) {this.x = amount;},
		setTop   : function(amount) {this.y = amount;},
		setRight : function(amount) {this.x = amount -image[this.frame].width;},
		setBottom: function(amount) {this.y = amount -image[this.frame].height;},
					
		setCenterX: function(amount) {this.x = amount -image[this.frame].width /2;},
		setCenterY: function(amount) {this.y = amount -image[this.frame].height/2;},
					
		getLeft  : function() {return this.x;},
		getTop   : function() {return this.y;},
		getRight : function() {return this.x +image[this.frame].width ;},
		getBottom: function() {return this.y +image[this.frame].height;},
					
		getCenterX: function() {return this.x +image[this.frame].width /2;},
		getCenterY: function() {return this.y +image[this.frame].height/2;},
					
		draw: function()
		{
			context.drawImage(image[this.frame], this.x, this.y);
		},
		drawOffset: function(offsetX)
		{
			context.drawImage(image[this.frame], this.x +offsetX, this.y);
		},
		
		getSquare: function(offsetX)
		{
			return [this.x +offsetX, this.y, this.x +image[this.frame].width +offsetX, this.y +image[this.frame].height];
		},
		
		getSquareHalved: function()
		{
			return [this.x +image[this.frame].width/4, this.y, this.x +image[this.frame].width *3/4, this.y +image[this.frame].height];
		}
	}
				
	return returner;
}

function DiAnimation(max)
{
	var returner = 
	{
		counterMax: 0,
		counterCurrent: 0,
		bPositive: false,
		
		update: function()
		{
			//Positive Animation
			if (this.bPositive && this.counterCurrent < this.counterMax)
			{
				//Advance Animation
				this.counterCurrent++;

				//Return that animation is updated
				return true;
			}
			else
			//Negative Animation
            if (!this.bPositive && this.counterCurrent > 0)
            {
                //Advance Animation
                this.counterCurrent--;

                //Return that animation is updated
                return true;
            }

			//Return that animation is not updated
			return false;
		},
		
		//Commands
		startFromBeggining: function() {this.counterCurrent = 0; this.bPositive = true;},
		startFromEnd:       function() {this.counterCurrent = this.counterMax; this.bPositive = false;},
		flip:               function() {this.bPositive = !this.bPositive;},
		
		start: function(frameTime)
		{
			//Count Frames
			this.counterMax = frameTime;
			this.counterCurrent = 0;
			
			//Start Animation
			this.bPositive = true;
		},
		
		//Isers
		isPositive: function() {return this.bPositive;},
		isAtStart : function() {return this.counterCurrent == 0 && !this.bPositive;},
		isAtEnd   : function() {return this.counterCurrent == this.counterMax && this.bPositive;},
		isRunning : function() 
		{
			return this.counterCurrent > 0 && !this.bPositive
				|| this.counterCurrent < this.counterMax && this.bPositive;
		},
		
		//Getters
		getDistance: function(amount) {return amount *this.counterCurrent /this.counterMax;},
		
		//Setters
		setMax : function(amount) {this.counterMax = amount;},
		setCounter: function(amount) {this.counterCurrent = amount;},
	}
	
	//Constructor
	//Set Max
	returner.counterMax = max;
			
	//Returner
	return returner;
}
			
function Ground()
{
	//Create
	var returner = 
	{
		image: DiPoint(15),
		width: 3,
		selfDestruct: false,
		selfDestructTimer: -1,
		
		setRight: function(amount) {this.image.x = amount -(image[15].width *this.width);},
		setCenterX: function(amount) {this.image.x = amount -(image[15].width *this.width)/2;},
		
		getRight: function() {return this.image.x +(this.width *image[15].width);},
		getCenterX: function() {return this.image.x +(this.width *image[15].width)/2;},
		
		setWidth: function(amount) {this.width = amount;},
		getWidth: function() {return this.width *image[15].width;},
		
		getGroundLevel: function() {return this.image.y +image[15].height/4;},
		
		update: function() 
		{
			//If it's being destroyed
			if (this.selfDestructTimer > -1)
			{
				//Advance animation and check if it finished
				if (++this.selfDestructTimer >= (12 *this.width)/2)
				{
					//Make ground off-screen
					this.image.setBottom(height*2);
					
					//Reset SelfDestruct
					this.selfDestruct = false;
					this.selfDestructTimer = -3;
				}
			}
		},
		draw: function() 
		{
			for (i = 0; i < this.width; i++)
			{
				var imageN;
				if (i == 0) imageN = 0; else
				if (i == this.width -1) imageN = 2;
				else imageN = 1;
				
				context.drawImage(image[this.image.frame +imageN], this.image.x +image[this.image.frame].width *i, this.image.y);
			}
		},
		
		drawOffset: function(offsetX) 
		{
			for (i = 0; i < this.width; i++)
			{
				if (this.selfDestructTimer > (12 *this.width)/2/2)
					this.image.frame = 18;
				
				var imageN;
				if (i == 0) imageN = 0; else
				if (i == this.width -1) imageN = 2;
				else imageN = 1;
				
				context.drawImage(image[this.image.frame +imageN], this.image.x +image[this.image.frame].width *i +offsetX, this.image.y);
			}
		}
	}
	
	//Init
	
	//Return
	return returner;
}
		
function Character()
{
	//Create
	var returner = 
	{
		//Extends diPoint
		image: DiPoint(28),
		
		//State
		RUNNING: 0,
		FALLING: 1,
		JUMPING: 2,
	
		//Animation
		animation: DiAnimation(24),
		aJump: 15,
		
		//AirJump
		pAirJump: DiPoint(40),
		aAirJump: DiAnimation(15),
		canAirJump: true,
		
		//Character State
		state: 1,
		
		//Frame
		stateFrame: 8,
		currentFrame: 0,
		
		//Shield & Land
		isShielded: false,
		justLanded: false,
		walkingOn: 0,
		
		//Magic Circle
		circleSize: 0,
		visualCircleSize: 0,
		
		update: function(groundLevel, jumpHeight)
		{
			if (this.justLanded) this.justLanded = false;
			
			//Update state
			switch (this.state)
			{
				case this.RUNNING:
					//If running off edge, fall down
					if (this.image.y +image[this.image.frame].height != groundLevel)
					{
						this.state = this.FALLING;
						this.stateFrame = 8;
						this.currentFrame = 0;
					}
					break;
				case this.FALLING:
					//Apply gravity
					this.image.y += jumpHeight /12;

					//If fell on ground
					if (this.image.y +image[this.image.frame].height >= groundLevel
					&&  this.image.y +image[this.image.frame].height <  groundLevel +jumpHeight /12)
					{
						//Set character on top of ground
						this.image.y = groundLevel -image[this.image.frame].height;

						//Start Walking
						this.state = this.RUNNING;
						this.stateFrame = 0;
						this.currentFrame = 0;

						this.justLanded = true;
						this.canAirJump = true;
					}
					break;
				case this.JUMPING:
					//Keep jumping
					this.image.y -= jumpHeight /15;
					
					//If animation reaches end
					if (this.aJump > 15)
					{
						//Start Falling
						this.state = this.FALLING;
						this.stateFrame = 8;
						this.currentFrame = 0;
					}

					//Advance animation
					this.aJump++;
					break;
			}
			
			//Animation
			if (this.animation.update())
				if (this.animation.counterCurrent %4 == 0)
				{
					this.currentFrame++;
					if (this.currentFrame >= 8
					|| (this.stateFrame != 0 && this.currentFrame >= 1)) 
						this.currentFrame = 0;
					
					if (this.animation.isAtEnd()) 
						this.animation.startFromBeggining();
						
					//if ((this.currentFrame == 1 ||  this.currentFrame == 5)
					//&&  this.stateFrame == 0)
					//	GameSurface.playSound(0);
				}

			//Magic Circle
			if (this.visualCircleSize > this.circleSize) this.visualCircleSize -= 4; else
			if (this.visualCircleSize < this.circleSize) this.visualCircleSize += 4;

			//if (this.aAirJump.update())
			//	invisJump.setAlpha(aAirJump.getDistance(255));

			this.pAirJump.changeX(-4);
		}, //end update
		
		draw: function()
		{
			var alpha = context.globalAlpha;
			
			//pAirJump
			if (this.aAirJump.update())
			{
				context.globalAlpha = this.aAirJump.getDistance(1);
				this.pAirJump.draw();
			}
			
			//Alpha
			context.globalAlpha = 0.3;
			
			//Magic Circle
			context.beginPath();
			context.arc(this.image.getCenterX(), this.image.getCenterY(), 
				this.visualCircleSize, 0, 2 * Math.PI, false);
			context.fillStyle = 'black';
			context.fill();
			
			//Alpha
			context.globalAlpha = alpha;
			
			context.fillStyle = 'white';
			
			//Shield Back
			if (this.isShielded)
				context.drawImage(image[39], 
					this.image.x, this.image.y);
			
			//Character
			context.drawImage(image[this.image.frame +this.stateFrame +this.currentFrame], this.image.x, this.image.y);
		
			//Shield Front
			if (this.isShielded)
				context.drawImage(image[38], 
					this.image.x, this.image.y);
		},
		
		drawSimple: function()
		{
			context.drawImage(image[this.image.frame +this.currentFrame], this.image.x, this.image.y);
		},
		
		animate: function()
		{
			//Animation
			if (this.animation.update())
				if (this.animation.counterCurrent %4 == 0)
				{
					this.currentFrame++;
					if (this.currentFrame >= 8)
						this.currentFrame = 0;
					
					if (this.animation.isAtEnd()) 
						this.animation.startFromBeggining();
						
					//if ((this.currentFrame == 1 ||  this.currentFrame == 5)
					//&&  this.stateFrame == 0)
					//	GameSurface.playSound(0);
				}
		},
		
		jump: function()
		{
			if (true)
			//if (this.aJump > 5)
            if (this.canAirJump || this.circleSize > 0)
            {
                //Use Mana
                if (!this.canAirJump) this.circleSize -= 36;// *GameSurface.density;
                else
                //Waste Air Jump
                if (this.state == this.FALLING || this.state == this.JUMPING)
				{
						this.canAirJump = false;
						this.pAirJump.setCenterY(this.image.getBottom());
						this.pAirJump.setCenterX(this.image.getCenterX());
						this.aAirJump.startFromEnd();
				}

                //Jump Animation
                this.state = this.JUMPING;
                this.stateFrame = 9;
                this.currentFrame = 0;
                this.aJump = 0;

                //Sound
                //GameSurface.playSound(1);
            }
		},
		
		giveShield: function() {this.isShielded = true;},
		loseShield: function() {this.isShielded = fale;},
		
		addManaLevel: function()
		{
			//If circleSize smaller than max size
			if (this.circleSize <  108)
			{
				//Make circle bigger
				this.circleSize += 36;
				//GameSurface.playSound(3);
			}
			//circleSize greater or equal to max size
			else
			{
				//Remove circle
				this.circleSize = 0;
				//GameSurface.playSound(4);
			}
		},
		
		loseMana: function() {this.circleSize = 0;}
	}
	
	//Constructor
	returner.pAirJump.setRight(0);
	
	//returner.animation.startFromBeggining();
	
	returner.animation.startFromBeggining();
	
	//Return
	return returner;
}
		
function Background()
{
	//Create Background
	var returner =
	{
		cloud1: DiPoint(3),
		cloud2: DiPoint(3),
		cloud3: DiPoint(4),
		mountain: [DiPoint(0), DiPoint(2), DiPoint(1)],
		lastMountain: 2,
		counter: 0,
		update: function(cameraX)
		{
			if (++this.counter == 5)
			{
				this.counter = 0;
							
				this.cloud1.changeX(1);
				if (this.cloud1.getLeft() -cameraX/12 > width)
					this.cloud1.setRight(cameraX/12);
        	
				this.cloud2.changeX(1);
				if (this.cloud2.getLeft() -cameraX/12 > width)
					this.cloud2.setRight(cameraX/12);
								
				this.cloud3.changeX(2);
				if (this.cloud3.getLeft() -cameraX/6 > width)
					this.cloud3.setRight(cameraX/6);
					
				return true;
			}
			
			return false;
		},
		draw: function()
		{
			this.cloud1.draw();
			this.cloud2.draw();
			
			this.mountain[0].draw();
			this.mountain[1].draw();
			this.mountain[2].draw();
			
			this.cloud3.draw();
		},
		drawOffset: function(offsetX)
		{
			this.cloud1.drawOffset(offsetX/12);
			this.cloud2.drawOffset(offsetX/12);
			
			this.mountain[0].drawOffset(offsetX/9);
			this.mountain[1].drawOffset(offsetX/9);
			this.mountain[2].drawOffset(offsetX/9);
			
			this.cloud3.drawOffset(offsetX/6);
		},
		
		checkLimits: function(cameraX)
		{
			if (this.cloud1.getRight() -cameraX/12 < 0)
				this.cloud1.setLeft(cameraX/12 +width);
			
			if (this.cloud2.getRight() -cameraX/12 < 0)
				this.cloud2.setLeft(cameraX/12 +width);
				
			for (var i = 0; i < 3; i++)
			if (this.mountain[i].getRight() -cameraX/9 < 0)
			{
				//Set Frame
				this.mountain[i].frame = getRandomInt(0, 1);
				if (this.mountain[i].frame == this.mountain[this.lastMountain].frame)
					this.mountain[i].frame = 2;
				
				//Set X
				if (this.mountain[this.lastMountain].getRight() -cameraX/9 > width)
					this.mountain[i].setLeft(this.mountain[this.lastMountain].getRight());
				else
					this.mountain[i].setLeft(cameraX/9 +width);
					
				//Set Y
				if (this.mountain[i].frame == 2)
					this.mountain[i].setTop(0);
				else
					this.mountain[i].setBottom(height);

				//Set last mountain
				this.lastMountain = i;
			}
				
			if (this.cloud3.getRight() -cameraX/6 < 0)
				this.cloud3.setLeft(cameraX/6 +width);
		},
		
		materialize: function(cameraX)
		{
			this.cloud1.setLeft(this.cloud1.getLeft() -cameraX/12);
			this.cloud2.setLeft(this.cloud2.getLeft() -cameraX/12);
			
			for (i = 0; i < 3; i++)
				this.mountain[i].setLeft(this.mountain[i].getLeft() -cameraX/9);
			
			this.cloud3.setLeft(this.cloud3.getLeft() -cameraX/6);
		}
	}
				
	//Prepare Background
	returner.cloud1.setCenterX(width/4);

	returner.cloud2.setCenterX(width *3/4);
	returner.cloud2.setCenterY(height *3/4);

	returner.cloud3.setRight (width);
	returner.cloud3.setBottom(height/2);
			
	returner.mountain[0].setBottom(height);
	returner.mountain[0].setCenterX(0);
				
	returner.mountain[1].setLeft(width -image[returner.mountain[1].frame].width *2/3);
				
	returner.mountain[2].setLeft(returner.mountain[1].getRight());
	returner.mountain[2].setBottom(height);
				
	//Return Background
	return returner;
}
			
function MainMenu(bHardRestart)
{
	//Create Menu
	var returner = 
	{
		aBasic: DiAnimation(10),
		ground: Ground(3),
		tree0: DiPoint(5),
		tree1: DiPoint(6),
		title: DiPoint(7),
		buttonStart: DiPoint(8),
		buttonExtra: DiPoint(8),
		buttonMute: DiPoint(26),
		bDraw: true,
		nextMenu: 0,
		hardRestart: bHardRestart,
		update: function()
		{
			//Input
			if (input)
			{
				input = false;
				
				if (this.buttonStart.isTouched(touchX, touchY))
					this.destroy(2); else
				if (this.buttonExtra.isTouched(touchX, touchY))
					this.destroy(1); else
				if (this.buttonMute.isTouched(touchX, touchY))
				{
					if (bSound)
					{
						this.buttonMute.frame = 27;
						bSound = false;
					}
					else
					{
						this.buttonMute.frame = 26;
						bSound = true;
					}
				}
				
				sound.play();
			}
			
			//Update menu
			if (this.aBasic.update())
			{
				if (this.aBasic.isAtStart())
					return this.nextMenu;
					
				bDraw = true;
			}
			
			//Move background
			if (background.update(0))
				bDraw = true;
		},
		draw: function()
		{
			//Background
			background.draw();
			
			if (this.hardRestart && this.aBasic.bPositive)
				context.globalAlpha = this.aBasic.getDistance(10) /10;
			
			//Ground
			this.ground.draw();
			
			//Trees
			this.tree0.draw();
			this.tree1.draw();
			
			//Alpha
			context.globalAlpha = this.aBasic.getDistance(10) /10;
			
			//Title
			this.title.draw();
			
			//Buttons
			this.buttonStart.draw();
			this.buttonExtra.draw();
			//this.buttonMute.draw();
			
			//Texts
			//var n = 
			context.shadowColor = "rgba(0, 0, 0, 1)";
			context.fillText('Start', this.buttonStart.getCenterX(), this.buttonStart.getCenterY() +fontSize/2);
			context.fillText('Extra', this.buttonExtra.getCenterX(), this.buttonExtra.getCenterY() +fontSize/2);
			context.shadowColor = "rgba(0, 0, 0, 0)";
			
			//Reset alpha
			context.globalAlpha = 1;
		},
		
		destroy: function(menu)
		{
			this.nextMenu = menu;
			this.aBasic.startFromEnd();
		}
	}
				
	//Prepare Menu
	//Animation
	returner.aBasic.startFromBeggining();
	
	//Ground
	returner.ground.setWidth(width /image[15].width +1);
	returner.ground.setCenterX(width/2);
	returner.ground.image.setBottom(height);
	
	//Trees
	returner.tree0.setCenterX(width /4);
	returner.tree0.setBottom (returner.ground.getGroundLevel());

	returner.tree1.setCenterX(width *5/6);
	returner.tree1.setBottom (returner.ground.getGroundLevel());
						
	//Title
	returner.title.setCenterX(width /2);
	returner.title.setCenterY(height/4);
				
	//Buttons
	returner.buttonStart.setCenterX(width    /3);
	returner.buttonStart.setCenterY(height *2/3);
	
	returner.buttonExtra.setCenterX(width  *2/3);
	returner.buttonExtra.setCenterY(height *2/3);
				
	returner.buttonMute.setRight (width  -image[returner.buttonMute.frame].width  /2);
	returner.buttonMute.setBottom(height -image[returner.buttonMute.frame].height /2);
				
	//Return Menu
	return returner;
}

function ExtraMenu()
{
	//Create Menu
	var returner = 
	{
		aBasic: DiAnimation(10),
		
		//Environment
		ground: Ground(3),
		tree0: DiPoint(5),
		tree1: DiPoint(6),
		
		//Dark Dimension
		darkDimensionLogo: DiPoint(10),
		
		//Back Buttons
		buttonBack: DiPoint(8),
		
		//Change Character
		charState: -1,
		aChangeChar: 0,
		character: Character(),
		buttonChangeChar: DiPoint(8),
		
		//Etc
		bDraw: true,
		nextMenu: 0,
		update: function()
		{
			//Input
			if (input)
			{
				input = false;
				
				if (this.buttonBack.isTouched(touchX, touchY))
					this.destroy(0); else
				if (this.buttonChangeChar.isTouched(touchX, touchY))
					this.charState = 0;
			}
			
			//Update menu
			if (this.aBasic.update())
			{
				if (this.aBasic.isAtStart())
					return this.nextMenu;
				bDraw = true;
			}
			
			//Move background
			if (background.update(0))
				bDraw = true;
				
			//Character
			this.character.animate();
			
			if(this.charState >= 0)
			{
				this.aChangeChar++;
				
				this.character.image.setLeft(width * 13/16 +(width *3/16 *Math.cos(Math.radians(90 -(this.aChangeChar*180/10)))));
				this.character.image.setBottom(this.ground.getGroundLevel() +image[this.character.image.frame].height +(image[this.character.image.frame].height *Math.sin(Math.radians(270+(this.aChangeChar*180/10)))));
				
				if (this.aChangeChar == 10)
				{
					if (bFirstChar)
					{
						bFirstChar = false;
						//change char
						image[28].src = 'images/diment_run_0.png';
						image[29].src = 'images/diment_run_1.png';
						image[30].src = 'images/diment_run_2.png';
						image[31].src = 'images/diment_run_3.png';
						image[32].src = 'images/diment_run_4.png';
						image[33].src = 'images/diment_run_5.png';
						image[34].src = 'images/diment_run_6.png';
						image[35].src = 'images/diment_run_7.png';
						
						image[36].src = 'images/diment_fall.png';
						image[37].src = 'images/diment_jump.png';
					}
					else
					{
						bFirstChar = true;
						image[28].src = 'images/darek_run_0.png';
						image[29].src = 'images/darek_run_1.png';
						image[30].src = 'images/darek_run_2.png';
						image[31].src = 'images/darek_run_3.png';
						image[32].src = 'images/darek_run_4.png';
						image[33].src = 'images/darek_run_5.png';
						image[34].src = 'images/darek_run_6.png';
						image[35].src = 'images/darek_run_7.png';
						
						image[36].src = 'images/darek_fall.png';
						image[37].src = 'images/darek_jump.png';
					}
				}else
				if (this.aChangeChar >= 20)
				{
					this.charState = -1;
					this.aChangeChar = 0;
				}
			}
				
			//If it's destroyed, return next action
			//...
		},
		draw: function()
		{
			//Background
			background.draw();
			
			//Ground
			this.ground.draw();
			
			//Trees
			this.tree0.draw();
			this.tree1.draw();
			
			//Alpha
			context.globalAlpha = this.aBasic.getDistance(10) /10;
			
			//Dark Dimension
			this.darkDimensionLogo.draw();
			
			//Character
			this.character.drawSimple();
			
			//Buttons
			this.buttonBack.draw();
			this.buttonChangeChar.draw();
			
			//Texts
			context.shadowColor = "rgba(0, 0, 0, 1)";
			context.fillText('Back', this.buttonBack.getCenterX(), this.buttonBack.getCenterY() +fontSize/2);
			context.fillText('Change', this.buttonChangeChar.getCenterX(), this.buttonChangeChar.getCenterY() +fontSize/2);
			
			context.fillText('Made by', this.darkDimensionLogo.getCenterX(), this.darkDimensionLogo.getTop());
			context.fillText('Dark Dimension', this.darkDimensionLogo.getCenterX(), this.darkDimensionLogo.getBottom() +fontSize);
			
			context.shadowColor = "rgba(0, 0, 0, 0)";
			
			//Reset alpha
			context.globalAlpha = 1;
		},
		
		destroy: function(menu)
		{
			this.nextMenu = menu;
			this.aBasic.startFromEnd();
		}
	}
				
	//Prepare Menu
	
	//Animation
	returner.aBasic.startFromBeggining();
	
	//Ground
	returner.ground.setWidth(width /image[15].width +1);
	returner.ground.setCenterX(width/2);
	returner.ground.image.setBottom(height);
	
	//Trees
	returner.tree0.setCenterX(width /4);
	returner.tree0.setBottom (returner.ground.getGroundLevel());

	returner.tree1.setCenterX(width *5/6);
	returner.tree1.setBottom (returner.ground.getGroundLevel());
						
	//Dark Dimension
    returner.darkDimensionLogo.setCenterX(width/2);
    returner.darkDimensionLogo.setCenterY(height/2);
	
	//Character
	returner.character.image.setLeft(width * 13/16);
	returner.character.image.setBottom(returner.ground.getGroundLevel());
			
	//Buttons
	returner.buttonBack.setRight(width -image[returner.buttonBack.frame].width/2);
	returner.buttonBack.setTop(image[returner.buttonBack.frame].height/2);
	
	//Change Character
	returner.buttonChangeChar.setCenterX(returner.character.image.getCenterX());
	returner.buttonChangeChar.setTop(returner.character.image.getBottom());
				
	//Return Menu
	return returner;
}

function GameMenu(bHardRestart)
{
	//Create menu
	returner = 
	{
		//Basic Animation
		aBasic: DiAnimation(10),
		bDraw: true,
		
		//Important Values
		//randomizer
		paused: false,
		gameRunning: -1,
		hardReset: false,
		hardRestart: bHardRestart,
		aStart: DiAnimation(50),
		
		//Camera
		cameraX: 0,
		speed: 16,
		highScore: localStorage.ritle_high_score,
		score: 0,
		
		//Ground
		groundLevel: [height*1/5, height*2/5, height*3/5, height*4/5],
		ground: [Ground(3), Ground(3), Ground(3), Ground(3), Ground(3)],
		lastGround: 4,
		
		//Trees
		tree: [DiPoint(5), DiPoint(6), DiPoint(6), DiPoint(6)],
		lastTree0: DiPoint(5),
		lastTree1: DiPoint(6),
		
		//Pick ups & enemies
		pickUp: [DiPoint(21), DiPoint(21)],
		enemy: [DiPoint(25), DiPoint(25)],
		doubleScoreTimer: DiAnimation(250),
		
		//Character
		character: Character(),
		
		//Crystal Show - UI
		diCrystal: DiPoint(21),
		dCrystals: 0,
		aCrystal: DiAnimation(16),
		aCrystalDelay: DiAnimation(40),
		tutorialDelay: DiAnimation(120),
		
		buttonPause: DiPoint(8),
		buttonRestart: DiPoint(8),
		buttonBack: DiPoint(8),
		buttonResume: DiPoint(8),
		buttonMute: DiPoint(26),
		
		//Results
		aResults: DiAnimation(30),
		dResults: 0,
		shownCrystals: 0,
		shownScore: 0,
		shownTotal: 0,
		
		nextMenu: 0,
		
		update: function()
		{
			//Input
			if (input)
			{
				//Cancel input
				input = false;
				
				//Skip results
				if (this.aResults.isRunning())
				{
					switch (this.dResults)
					{
						case 1: this.shownCrystals = this.dCrystals; break;
						case 2: this.shownScore = Math.floor(this.score /100) -1; break;
						case 3: this.shownTotal = this.shownCrystals +this.shownScore -1; break;
						case 4:
							if (this.buttonRestart.isTouched(touchX, touchY))
							{
								this.nextMenu = 2;
								this.aBasic.counterMax = 10;
								this.aBasic.startFromEnd();

								if (this.gameRunning > 0)
									this.hardReset = true;
							} else
							if (this.buttonBack.isTouched(touchX, touchY))
							{
								this.nextMenu = 0;
								this.aBasic.counterMax = 10;
								this.aBasic.startFromEnd();

								if (this.gameRunning > 0)
									this.hardReset = true;
							}
					}
					this.aResults.counterCurrent = this.aResults.counterMax -1;
				}
				else
				//Pause Menu
				if (this.paused)
				{
					if (this.buttonResume.isTouched(touchX, touchY))
						this.paused = false; else
					if (this.buttonRestart.isTouched(touchX, touchY))
					{
						this.nextMenu = 2;
						this.aBasic.counterMax = 10;
						this.aBasic.startFromEnd();

						this.hardReset = true;
					} else
					if (this.buttonBack.isTouched(touchX, touchY))
					{
						this.nextMenu = 0;
						this.aBasic.counterMax = 10;
						this.aBasic.startFromEnd();

						this.hardReset = true;
					} else
					if (this.buttonMute.isTouched(touchX, touchY))
					{
						if (bSound)
						{
							this.buttonMute.frame = 27;
							bSound = false;
						}
						else
						{
							this.buttonMute.frame = 26;
							bSound = true;
						}
					}
				} else
				//Pause Button
				if (this.buttonPause.isTouched(touchX, touchY))
				{
					this.paused = true;
					if (!this.aCrystal.isPositive())
						this.aCrystal.flip();
				}
				else
					this.character.jump();
			} //End input
			
			if (this.paused); else
			//Game is running
			if (this.gameRunning != 0)
			{
				//Advance Camera
				this.cameraX += this.speed;
				
				//Check background props
				background.checkLimits(this.cameraX);
				
				//Ground
				var N = 5;//ground.length
				for (var i = 0; i < N; i++)
				{
					//Ground has left the screen
					if (this.ground[i].getRight() -this.cameraX/4 <= 0
					&&  this.gameRunning == -1)
					{
						this.ground[i].image.frame = 15;
						
						//Width
						if (this.score < 4000)	//5, 6, 7
							this.ground[i].setWidth(getRandomInt(5, 7)); else
						if (this.score < 9000)	//4, 5
							this.ground[i].setWidth(getRandomInt(4, 5)); else
						if (this.score < 15000)	//3, 4
							this.ground[i].setWidth(getRandomInt(3, 4));
						else				//2, 3
							this.ground[i].setWidth(getRandomInt(2, 3));

						//Coordinates X
						if (this.score < 2000)
							this.ground[i].image.setLeft(this.ground[this.lastGround].getRight()); else
						if (this.score < 6500)
							this.ground[i].image.setLeft(this.ground[this.lastGround].getRight() +image[15].width); else
						if (this.score < 12000)
							this.ground[i].image.setLeft(this.ground[this.lastGround].getRight() +image[15].width +image[15].width/2); else
						if (this.score < 17000)
							this.ground[i].image.setLeft(this.ground[this.lastGround].getRight() +image[15].width *2);
						else
							this.ground[i].image.setLeft(this.ground[this.lastGround].getRight() +image[15].width *3);

						//Coordinates Y
						this.ground[i].image.setTop( this.groundLevel[ getRandomInt(0, 2) ] -image[15].height/4 );

						//Same ground level
						if (this.ground[i].image.getTop() == this.ground[this.lastGround].image.getTop())
							this.ground[i].image.setTop( this.groundLevel[3] -image[15].height/4 );

						this.lastGround = i;
						
						//Items
						var item = getRandomInt(0, 99);
						if (item < 50) item = 0; else
						if (item < 60) item = 1; else
						if (item < 64) item = 3; else
						if (item < 67) item = 2;
						else item = -1;

						if (item != -1)
							//Cycle pickups
							for (var j = 0; j < 2; j++)
								if (this.pickUp[j].getRight() -this.cameraX/4 <= 0)
								{
									//Create this pickUp
									this.pickUp[j].frame = 21 +item;
									this.pickUp[j].setLeft(this.ground[i].image.x +getRandomInt(0, this.ground[i].getWidth() -image[this.pickUp[j].frame].width));
									this.pickUp[j].setBottom(this.ground[i].getGroundLevel());

									j = 2;
								}
						
						//Enemies
						item = -1;
						if (getRandomInt(0, 99) < 75 && this.ground[i].width > 2)
							item = 0;
						else
						if (this.ground[i].width < 6 && getRandomInt(0, 99) < 60 && this.score > 3000)
							this.ground[i].selfDestruct = true;
							
						if (item != -1)
							//Cycle Enemies
							for (j = 0; j < 2; j++)
								if (this.enemy[j].getRight() -this.cameraX/4 <= 0)
								{
									//Create Enemy
									this.enemy[j].setCenterX(this.ground[i].image.x +this.ground[i].getWidth() /3 *getRandomInt(1, 2));
									this.enemy[j].setBottom(this.ground[i].getGroundLevel());

									j = 2;
								}
						
						//Chance for trees
						//Ground is big enough and will not selfDestruct
						if (this.ground[i].width >= 3 && !this.ground[i].selfDestruct)
							//Random chance
							if (getRandomInt(0, 99) < 35)
								//Search all trees
								for (var j = 0; j < 4; j++)
									//Find first available tree
									if (this.tree[j].getRight() -this.cameraX/4 <= 0)
									{
										this.tree[j].frame = getRandomInt(5, 6);
										this.tree[j].setBottom(this.ground[i].getGroundLevel());
										this.tree[j].setCenterX(this.ground[i].image.x +(this.ground[i].getWidth() *getRandomInt(1, 4)/5 ));//this.ground[i].getLeft() +(this.ground[i].getWidth() *getRandomInt(1, 4)/5 ));
										
										j = 4;
									}
					}
					
					//Update ground -Self Destruct-
					this.ground[i].update();
				}
				
				//Opening animation
				if (this.aStart.update())
					this.character.image.setRight(this.aStart.getDistance(image[this.character.image.frame].width *3));
				
				//Check if character moved to next ground
				if (this.character.image.getCenterX() > this.ground[this.character.walkingOn].getRight() -this.cameraX/4)
					if (++this.character.walkingOn >= 5) this.character.walkingOn = 0;
				
				//Character Update
				if ((this.character.image.getCenterX() > this.ground[this.character.walkingOn].image.getLeft()  
					-this.cameraX/4 || this.aBasic.isRunning()) && this.gameRunning == -1)
					this.character.update(this.ground[this.character.walkingOn].getGroundLevel(), this.groundLevel[1]);
				else
					this.character.update(-height*2, this.groundLevel[1]);
					
				//Activate ground selfDestruct if there is
				if (this.character.justLanded)
				if (this.ground[this.character.walkingOn].selfDestruct)
					this.ground[this.character.walkingOn].selfDestructTimer = 0;
					
				//PickUps
				for (var i = 0; i < 2; i++)
					if (this.pickUp[i].getRight() -this.cameraX/4 > 0)
						//if Character picked up something
						if (isColliding(this.character.image.getSquareHalved(0), this.pickUp[i].getSquare(-this.cameraX/4)))//character.getSquare(), cPickUp.getSquare(-cameraX / 4, 0))
						//&& gameRunning == -1)
						{
							switch (this.pickUp[i].frame -21)
							{
								case 0: //Memory Crystal
									this.dCrystals++;
									if (!this.aCrystal.isPositive())
										this.aCrystal.flip();
									//GameSurface.playSound(2);
									break;
								case 1: //Magic Mana
									this.character.addManaLevel();
									break;
								case 2: //Shield
									this.character.giveShield();
									//GameSurface.playSound(6);
									break;
								case 3: //Double Score
									this.doubleScoreTimer.startFromBeggining();
									//GameSurface.playSound(5);
									break;
							}
							
							//Remove pickUp
							this.pickUp[i].setRight(0);
						}
						
				//Enemies
				for (i = 0; i < 2; i++)
					if (this.enemy[i].getRight() -this.cameraX/4 > 0)
					{
						if (this.character.justLanded)
							if (this.character.image.getCenterX() > this.enemy[i].x -this.cameraX/4
							&&  this.character.image.getCenterX() < this.enemy[i].getRight() -this.cameraX/4)
							{
								if (this.character.isShielded)
									this.character.isShielded = false; else 
								if (this.character.circleSize > 0)
									this.character.circleSize = 0;
								else
								{
									this.aStart.startFromEnd();
									this.character.jump();
									this.destroy(0);
								}

								//GameSurface.playSound(7);
							}
					}
				
				//Game Over
				if (this.character.image.y > height && this.gameRunning == -1)
				{
					//GameSurface.playSound(7);
					this.destroy(1);
				}else
				//if game is ending, and it got to the final frame
				if (this.gameRunning > 0)
					if (this.gameRunning -this.cameraX/4 < 0)
					{
						//End game
						this.gameRunning = 0;

						//Fix camera so it has same angle as in main menu
						this.cameraX = (this.ground[this.lastGround].getCenterX() -width/2) *4;
					}
				
				//Survived this frame - award score
				if (!this.aBasic.isRunning() && this.gameRunning == -1)
					if (this.doubleScoreTimer.update())
						this.score += 2;
					else
						this.score++;
			}//End game is running
			else
			//Game is not running and its not paused
				background.update(this.cameraX);
				
			//if game is ended
			if (this.aResults.update())
			{
				//Game over updated
				switch (this.dResults)
				{
					case 0: //Menu comes in play
						break;
					case 1: //Count crystals
						if (this.dCrystals > 0)
							this.shownCrystals++;
						break;
					case 2: //Count Score
						if (Math.floor(this.score /100) > 0)
							this.shownScore++;
						break;
					case 3: //Count Total
						if (this.shownCrystals +this.shownScore > 0)
							this.shownTotal++;
						break;
					case 4: //Wait for input
						break;
				}
				
				//Stop updating and start next menu
				if (this.aResults.isAtEnd())
				{
					var changed = false;
					if (this.dResults < 4)
					{
						this.dResults++;
						changed = true;
					}
					switch (this.dResults)
					{
						case 1:
							if (this.dCrystals != 0)
								this.aResults.start( this.dCrystals );
							else
								this.aResults.start( 10 );
							break;
						case 2:
							if (Math.floor(this.score /100) != 0)
								this.aResults.start( Math.floor(this.score /100) );
							else
								this.aResults.start( 10 );
							break;
						case 3:
							if (this.shownCrystals +this.shownScore != 0)
								this.aResults.start( this.shownCrystals +this.shownScore );
							else
								this.aResults.start( 10 );
							break;
						case 4:
							this.aResults.start(50);
							break;
					}
					if (changed && this.dResults == 4) 
					if (this.highScore < this.shownTotal)
						localStorage.ritle_high_score = this.shownTotal;//Save High Score
				}
			}
			
			//Crystal Display
			if (this.aCrystalDelay.isRunning())
			if (!this.paused)
			{
				//Advance Delay
				this.aCrystalDelay.update();

				//Action when it's over
				if (this.aCrystalDelay.isAtEnd())
					this.aCrystal.startFromEnd();
			}
			//else
			if (this.aCrystal.update())
			{
				this.diCrystal.setTop( height -this.aCrystal.getDistance(image[this.diCrystal.frame].height) );//height -this.aCrystal.getDistance( image[this.diCrystal.frame].height() ));

				if (this.aCrystal.isAtEnd())
					this.aCrystalDelay.startFromBeggining();
			}
			
			//Redraw
			this.bDraw = true;
			
			//Menu destroyed
			if (this.aBasic.update())
			if (this.aBasic.isAtStart() && !this.aBasic.bPositive)
			{
				background.materialize(this.cameraX);
				return this.nextMenu;
			}
		},
		
		draw: function()
		{
			//Cancel draw
			bDraw = false;
			
			//Background
			background.drawOffset(-this.cameraX);
			
			//Hard reset/restart alpha
			if ((this.hardRestart && this.aBasic.bPositive )
			||  this.hardReset)
				context.globalAlpha = this.aBasic.getDistance(1);
			
			//Ground
			for (var i = 0; i < 5; i++)
				this.ground[i].drawOffset(-this.cameraX/4);
			
			//Trees
			this.tree[0].drawOffset(-this.cameraX/4);
			this.tree[1].drawOffset(-this.cameraX/4);
			
			this.lastTree0.drawOffset(-this.cameraX/4);
			this.lastTree1.drawOffset(-this.cameraX/4);
			
			//Alpha
			context.globalAlpha = this.aBasic.getDistance(1);
			
			//Spikes
			for (i = 0; i < 2; i++)
				if (this.enemy[i].getRight() -this.cameraX/4 > 0)
					this.enemy[i].drawOffset(-this.cameraX/4);
			
			//Pick ups
			for (var i = 0; i < 2; i++)
				if (this.pickUp[i].getRight() > 0)
					this.pickUp[i].drawOffset(-this.cameraX/4);
			
			//Character
			this.character.draw();
			
			//Crystals
			this.diCrystal.draw();
			
			//Results
			if (this.dResults == 4)
			{
				this.buttonBack.draw();
				this.buttonRestart.draw();
			} else
			//Pause
			if (this.paused)
			{
				this.buttonBack.draw();
				this.buttonRestart.draw();
				this.buttonResume.draw();
				//this.buttonMute.draw();
			}
			else
			if (this.gameRunning == -1)
				this.buttonPause.draw();
			
			//Texts
			context.shadowColor = "rgba(0, 0, 0, 1)";
			
			//Score
			context.fillText("Score:", width/2, 5 +fontSize);
			if (this.doubleScoreTimer.isRunning())
				context.fillStyle = "rgb(143, 231, 134)";
			context.fillText(this.score, width/2, 10 +fontSize*2);
			if (this.doubleScoreTimer.isRunning)
				context.fillStyle = "white";
			
			//Crystals
			if (!this.aCrystal.isAtStart())
			{
				context.fillText("x ", this.diCrystal.getRight(), this.diCrystal.getCenterY() +fontSize/2);
				context.fillText(this.dCrystals, this.diCrystal.getCenterX() *4, this.diCrystal.getCenterY() +fontSize/2);
			}
			
			//Results
			//Draw Results
			if (this.aResults.isRunning())
			{
				context.fillText("Results:", width/2, fontSize*4);
				
				context.fillText("Crystals:"			, width/3, fontSize*5 +2);
				context.fillText("Score (Points /100):"	, width/3, fontSize*6 +4);
				context.fillText("Total:"				, width/3, fontSize*7 +6);
				context.fillText("High Score:"			, width/3, fontSize*8 +8);
				
				//Crystals
				if (this.dResults == 1)
					context.fillStyle = "rgb(143, 231, 134)";
					
				context.fillText(this.shownCrystals	, width*2/3, fontSize*5 +2);
				
				if (this.dResults == 1)
					context.fillStyle = "white";
					
				//Score
				if (this.dResults == 2)
					context.fillStyle = "rgb(143, 231, 134)";
					
				context.fillText(this.shownScore	, width*2/3, fontSize*6 +4);
				
				if (this.dResults == 2)
					context.fillStyle = "white";
				
				//Total
				if (this.dResults == 3)
					context.fillStyle = "rgb(143, 231, 134)";
					
				context.fillText(this.shownTotal	, width*2/3, fontSize*7 +6);
				
				if (this.dResults == 3)
					context.fillStyle = "white";
					
				//High Score
				context.fillText(this.highScore		, width*2/3, fontSize*8 +8);
					
				if (this.shownTotal > this.highScore)
					context.fillText("New High Score!"	, width/2, fontSize*9 +10);
					
				//
				if (this.dResults == 4)
				{
					context.fillText("Restart"	, this.buttonRestart.getCenterX(), this.buttonRestart.getCenterY() +fontSize/2);
					context.fillText("Main Menu", this.buttonBack.getCenterX(), this.buttonBack.getCenterY() +fontSize/2);
				} else
					context.fillText("Click anywhere to continue", 
						width/2, 
						height *8/9 +fontSize/2);
			} else
			if (this.paused)
			{
				context.fillText("Restart"	, 
					this.buttonRestart.getCenterX(), 
					this.buttonRestart.getCenterY() +fontSize/2);
				context.fillText("Resume"	, 
					this.buttonResume.getCenterX(), 
					this.buttonResume.getCenterY() +fontSize/2);
				context.fillText("Main Menu", 
					this.buttonBack.getCenterX(), 
					this.buttonBack.getCenterY() +fontSize/2);
			} else
			if (this.gameRunning == -1)
				context.fillText("Pause", 
					this.buttonPause.getCenterX(), 
					this.buttonPause.getCenterY() +fontSize/2);
					
			context.shadowColor = "rgba(0, 0, 0, 0)";
			
			context.globalAlpha = 1;
		},
		destroy: function(menu)
		{
			if (this.gameRunning == -1)
			{
				this.nextMenu = menu;

				//Find first not visible ground
				//Create Main Menu pattern there
				//Make the rest not visible
				var i = this.character.walkingOn;
				var startingPoint = -1;
				do
				{
					//if ground is right from screen
					if (this.ground[i].image.x -this.cameraX/4 > width)
						//First one becomes main menu pattern
						if (startingPoint == -1)
						{
							//Create Main Menu Patter here
							this.ground[i].width = width /image[15].width +1;
							this.ground[i].image.setBottom(height);
							this.ground[i].selfDestruct = false;
							
							startingPoint = this.ground[i].getCenterX() -width/2;//this.ground[iii].getCenterX() -width/2;
							
							//Last Trees
							this.lastTree0.setCenterX(startingPoint +width   /4);
							this.lastTree0.setBottom(this.ground[i].getGroundLevel());

							this.lastTree1.setCenterX(startingPoint +width *5/6);
							this.lastTree1.setBottom(this.ground[i].getGroundLevel());
							
							this.lastGround = i;
						}
						//The rest of them are gone
						else
							this.ground[i].image.y = height*2;
					
					i++;
					if (i == 5)
						i = 0;
				} while (i != this.character.walkingOn);
			
				//Remove unnecessary items
				for (jjj = 0; jjj < 2; jjj++)
					if (this.pickUp[jjj].x -this.cameraX/4 > width)
						this.pickUp[jjj].setRight(0);

				//Remove unnecessary enemies(int) (startingPoint -(cameraX/4) /(4 *GameSurface.density *speed));
				for (jjj = 0; jjj < 2; jjj++)
					if (this.enemy[jjj].x -this.cameraX/4 > width)
						this.enemy[jjj].setRight(0);

				for (jjj = 0; jjj < 4; jjj++)
					if (this.tree[jjj].x -this.cameraX/4 > width)
						this.tree[jjj].setRight(0);
				
				//Create game countdown
				this.gameRunning = startingPoint;

				//Start showing results
				this.aResults.setMax(30);
				this.aResults.startFromBeggining();
				this.dResults = 0;
			}
		}
	}
	
	//Constructor
	
	returner.aStart.startFromBeggining();
	returner.aBasic.startFromBeggining();
	
	//Ground
	
		//First Ground
		returner.ground[0].setWidth(width /image[15].width +1);
		returner.ground[0].setCenterX(width/2);
		returner.ground[0].image.setBottom(height);
		
		//Rest Grounds
		for (var i = 1; i < 5; i++)
		{
			//Init ground
			returner.ground[i].setWidth(getRandomInt(3, 7));
			returner.ground[i].image.setLeft(returner.ground[i-1].getRight());

			//Randomize one of the ground levels except the last
			returner.ground[i].image.setTop( returner.groundLevel[ getRandomInt(0, 2) ] -image[15].height/4);//randomizer.nextInt(3) ] -DiPoint.getHeight(14)/4 );

			//If it matches the previous
			if (returner.ground[i].image.getTop() == returner.ground[i -1].image.getTop())
				//Give it the last one
				returner.ground[i].image.setTop( returner.groundLevel[3] -image[15].height/4 );
		}
		
	//Constructor
	if (returner.highScore == undefined)
		returner.highScore = 0;
	
	//Trees
		//First two trees are fixed
		returner.tree[0].setCenterX(width /4);
		returner.tree[0].setBottom (returner.ground[0].getGroundLevel());

		returner.tree[1].setCenterX(width *5/6);
		returner.tree[1].setBottom (returner.ground[0].getGroundLevel());
		
		//Rest are on invalid state (for reseting)
		for (var i = 2; i < 4; i++)
			returner.tree[i].setRight(0);

		//Last two remain invalid until game stops
		returner.lastTree0.setRight(0);
		returner.lastTree1.setRight(0);
		
	//Pick ups & Enemies
		for (var i = 0; i < 2; i++)
		{
			returner.pickUp[i].setRight(0);
			returner.enemy[i].setRight(0);
		}
			
	//Character
	returner.character.image.setRight(0);
	returner.character.image.setBottom(returner.ground[0].getGroundLevel() -1);
	
	//Crystals - UI
	returner.diCrystal.setLeft(0);
	returner.diCrystal.setTop(height);
	
	returner.buttonPause.setLeft(image[returner.buttonPause.frame].width/2);
	returner.buttonPause.setTop(image[returner.buttonPause.frame].height/2);
	
	returner.buttonRestart.setCenterX(width /4);
	returner.buttonRestart.setCenterY(height *3/4);
	
	returner.buttonResume.setCenterX(width *2/4);
	returner.buttonResume.setCenterY(height *3/4);
	
	returner.buttonBack.setCenterX(width *3/4);
	returner.buttonBack.setCenterY(height *3/4);
	
	returner.buttonMute.setRight (width  -image[returner.buttonMute.frame].width  /2);
	returner.buttonMute.setBottom(height -image[returner.buttonMute.frame].height /2);
	
	//Return menu
	return returner;
}

// Converts from degrees to radians.
Math.radians = function(degrees) {
  return degrees * Math.PI / 180;
};

//Get random integer
function getRandomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

function isColliding(object1, object2)
{
    return  (object1[2] -object2[0] > 0)
		!=  (object1[0] -object2[2] > 0)
		&&  (object1[3] -object2[1] > 0)
		!=  (object1[1] -object2[3] > 0);
}


